package com.example.lotterysystem.service.activitystatus.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.service.ActivityService;
import com.example.lotterysystem.service.activitystatus.ActivityStatusManager;
import com.example.lotterysystem.service.activitystatus.operator.AbstractActivityOperator;
import com.example.lotterysystem.service.dto.ConvertActivityStatusDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


@Component
public class ActivityStatusManagerImpl implements ActivityStatusManager {

    private static final Logger logger = LoggerFactory.getLogger(ActivityStatusManagerImpl.class);
    @Autowired
    private final Map<String, AbstractActivityOperator> operatorMap = new HashMap<>(); //<类的名称,具体的对象>
    @Autowired
    private ActivityService activityService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //使用的是状态链,选择性转换
        //1.活动状态扭转有依赖性
        //2.状态扭转的条件可能会扩展,那么当前的写法维护性就会很差(当产生新的依赖时,活动扭转就必须要修改写法)

        if(CollectionUtils.isEmpty(operatorMap)){
            logger.warn("当前的 operator 为空");
            //表示当前的map里面没有对任何信息的处理方法
            return;
        }

        //map: 定义参数 <String ,AbstractActivityOperator>

        Map<String, AbstractActivityOperator> currMap = new HashMap<>(operatorMap);
        Boolean update = false;//用来判断是否更新
        //先处理:人员、奖品状态
        update = processConvertStatus(convertActivityStatusDTO,currMap,1);

        //后处理:活动
        /*if(update){
            //如果前面更新之后,但是活动没有更新,那么update就会是false
            //为了避免,就需要将条件进行单独处理
            processConvertStatus(convertActivityStatusDTO,currMap,2);
        }*/
        update = processConvertStatus(convertActivityStatusDTO,currMap,2) || update; //只要最后有一个为 true ,最后的结果就是true

        //更新缓存
        if(update){
            activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
        }

    }

    /**
     * 扭转状态
     * @param convertActivityStatusDTO
     * @param currMap
     * @param sequence
     * @return Boolean
     */
    private Boolean processConvertStatus(ConvertActivityStatusDTO convertActivityStatusDTO,
                                         Map<String, AbstractActivityOperator> currMap,
                                         int sequence) {
        Boolean update = false;
        //遍历 map 获取单个的operator
        Iterator<Map.Entry<String,AbstractActivityOperator>> iterator = currMap.entrySet().iterator();
        while (iterator.hasNext()){
            AbstractActivityOperator operator = iterator.next().getValue();
            //看单个的operator是否需要进行转换 : sequence是否一致
            if (operator.sequence()!=sequence
            || !operator.needConvert(convertActivityStatusDTO)){
                //对不上号,或者当前的 operator 不需要进行处理
                continue;
            }

            //需要转换,进行操作
            if(!operator.convert(convertActivityStatusDTO)){
                logger.info(""+operator.convert(convertActivityStatusDTO));
                //转换失败处理
                logger.error("{} 状态转换失败",operator.getClass().getName());
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_STATUS_CONVERT_ERROR);
            }

            //将map中删除当前operator(已经转换成功)
            iterator.remove();
            update = true;
        }

        //返回
        return update;
    }


    @Override
    public void rollbackHandlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //这里是强制转换
        //operatorMap: 活动、奖品、人员(对于回滚来说就不需要按照顺序了,此时奖品和人员都是必要回滚的)
        //活动是否需要进行回滚? --> 必须要(虽然活动本身不一定被回滚了,但是奖品初始化之后 INIT,活动也要进行初始化)
        //奖品都被初始化之后,那么该活动的奖品是肯定没有被抽完的
        for (AbstractActivityOperator operator : operatorMap.values()){
            operator.convert(convertActivityStatusDTO);
        }

        //更新缓存
        activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
    }
}
